import { computed, reactive, readonly, ref, watch } from 'vue'
import { syncRef } from '@vueuse/core'
import { defineStore, storeToRefs } from 'pinia'
import { useAccountStore } from '@/store/account'
import { useCreatorStore } from '@/store/creator'
import { locale, locales } from '@/i18n'
import { toDate } from '@/utils/string-helper'
import { useInfinite } from '@/compositions/request/infinite'
import { useDialog } from '@/compositions/viewer/dialog'
import { LANGUAGE } from '@/constant'
import { SEND_STATUS, TRANSLATE_STATUS } from '@/constant/chat'
import API from '@/http'

const TRANSLATE_COUNT = 29

export const useChatStore = defineStore('chat', () => {
  /**
   * {
   *   [id]: {
   *     id,
   *     uuid,
   *     avatar,
   *     username,
   *     nickname,
   *     isVip: boolean,     // 是否為購買 premium 的會員
   *     translate: boolean, // 是否要翻譯
   *     translateLang,      // 要翻譯成的語言
   *     messages: [
   *       {
   *         id
   *         timestamp
   *         content
   *         contentType: 'text' | 'photos'
   *         ext: JSON.parse({ toAff, fromAff, width, height }), // width, height 只有 contentType = 'photos' 才有
   *         self: boolean,
   *         status: SEND_STATUS,
   *         unread: boolean,
   *         langTable: {
   *           orig: 翻譯前的語言，當下語言的狀態為翻譯中時取用，避免畫面銜接不上
   *           'zh-tw': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'zh-cn': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'en': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'es': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'fr': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'de': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'th': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'vi': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'ja': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'ko': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'ru': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'pt': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'id': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'ar': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *           'hi': string(翻譯結果) | TRANSLATE_STATUS.PENDING | TRANSLATE_STATUS.TRANSLATING
   *         }
   *       }
   *     ]
   *   },
   *   ...
   * }
   */
  const userMap = reactive(new Map())
  const userHistoryFetcherMap = new Map()

  // 傳送成功只會通知你 sign id，我只好用這個來暫存 sign id 對應到的 toAff，才能直接從 userMap 查到
  const sendingMessagesMap = new Map()

  // 歷史聊天記錄表同步是否完成
  const ready = ref(false)

  const accountStore = useAccountStore()
  const { isLogin, isVip } = storeToRefs(accountStore)

  const translatorOpen = ref(isVip.value)
  syncRef(isVip, translatorOpen, { direction: 'ltr' })
  const openTranslator = () => (translatorOpen.value = true)
  const closeTranslator = () => (translatorOpen.value = false)
  const toggleTranslator = () => (translatorOpen.value = !translatorOpen.value)

  watch(
    isLogin,
    (login) => {
      if (login) {
        syncHistory()
      } else {
        clearALL()
      }
    },
    { immediate: true },
  )

  const usersSortByLatestMessage = computed(() => {
    const r = Array.from(userMap.values())
    r.sort((a, b) => {
      const av = a.messages[a.messages.length - 1]?.timestamp || -1
      const bv = b.messages[b.messages.length - 1]?.timestamp || -1
      return bv - av
    })
    return r
  })

  const totalUnreadCount = computed(() => {
    let r = 0
    userMap.forEach((user) => {
      r += user.messages.filter((m) => m.unread).length
    })
    return r
  })

  async function getUser(id) {
    await checkUserMapExists(id)
    return userMap.get(id)
  }

  async function pushSelfMessage(message) {
    const { sign: id, microtime: timestamp, content, msgType: contentType, ext: extJsonString } = message
    const ext = JSON.parse(extJsonString)
    const { toAff } = ext

    await checkUserMapExists(toAff)

    userMap.get(toAff).messages.push({
      id,
      timestamp,
      content,
      contentType,
      ext,
      self: true,
      status: SEND_STATUS.SENDING,
    })

    sendingMessagesMap.set(id, toAff)
  }

  function selfMessageSendSuccess(id) {
    selfMessageUpdate(id, 'status', SEND_STATUS.SUCCESS)

    sendingMessagesMap.delete(id)
  }

  function selfPhotoUploaded(id, url) {
    selfMessageUpdate(id, 'content', url)
  }

  function selfMessageUpdate(id, key, value) {
    if (!sendingMessagesMap.has(id)) {
      throw new Error('Self message success setting error...')
    }

    const toAff = sendingMessagesMap.get(id)

    const messages = userMap.get(toAff).messages
    for (let i = messages.length - 1; i >= 0; i--) {
      const message = messages[i]
      if (message.id === id) {
        message[key] = value
        break
      }
    }
  }

  async function pushOtherMessage(message) {
    const { sign: id, timestamp, content, content_type: contentType, ext: extJsonString } = message
    const ext = JSON.parse(extJsonString)
    const { fromAff } = ext

    const user = await getUser(fromAff)

    user.messages.push(
      buildMessageWithLangTable({
        id,
        timestamp: timestamp * 1000, // 後端傳來的沒有毫秒...XD
        content,
        contentType,
        ext,
        self: false,
        status: SEND_STATUS.SUCCESS,
        unread: true /* 後端無法完整解決前端暫時補一個上去的 */,
      }),
    )
    translateWhenNewMessage(user)
  }

  async function checkUserMapExists(aff) {
    const { getCreator } = useCreatorStore()
    const creator = await getCreator(aff)
    console.log('creatorchat', creator)
    if (!userMap.has(aff)) {
      initUser(
        aff,
        creator.uuid,
        creator.avatar,
        creator.username,
        creator.nickname,
        creator.is_vip,
        creator.tier || 1, // 添加默认值0，防止undefined
      )
    }
  }

  function syncHistory() {
    if (userMap.size > 0 || sendingMessagesMap.size > 0) {
      throw new Error('You cannot syncHistory, userMap or sendingMessagesMap still have data...')
    }

    ready.value = false
    API.Chat.getContactList()
      .then((d) => {
        for (const [, { info, message }] of Object.entries(d)) {
          // 這是聊天對象的資訊
          const { aff, avatar, username, nickname, is_vip, tier } = info
          const ext = transformExt(message.ext)

          // ext 格式有誤直接跳過了
          if (!ext) continue

          // 對象的 aff = 傳送給的 aff 那這筆訊息就是自己的
          // 此 uuid 是對方的
          const uuid = aff === ext.toAff ? message.to_id : message.from_uuid
          initUser(aff, uuid, avatar, username, nickname, is_vip, tier, [makeHistoryMessage(message, aff)])
        }
      })
      .catch((e) => console.warn(e))
      .finally(() => (ready.value = true))
  }

  async function loadNextHistory(otherAff, isInit = false) {
    await checkUserMapExists(otherAff)

    const { dataList, init, nextPage, noMore } = userHistoryFetcherMap.get(otherAff)
    if (noMore.value) {
      return
    }

    const user = userMap.get(otherAff)

    const action = (data) => {
      user.loading = false
      pushHistoryMessages(data, otherAff)
      user.noMore = noMore.value
      translateWhenNewMessage(user)
    }

    if (isInit && dataList.length === 0) {
      user.loading = true
      init(action)
    } else {
      user.loading = true
      nextPage(action)
    }
  }

  async function pushHistoryMessages(historyMessages, otherAff) {
    await checkUserMapExists(otherAff)
    const messages = userMap.get(otherAff).messages

    historyMessages.forEach((message, index) => {
      // 一開始 getContactList 會有第一筆，然後接下去的第一次 getHistory 的第一筆應該會是相同的，這時候要跳過
      if (index === 0 && messages[0] && messages[0].id === message.sign) {
        return
      }
      // ext 格式有誤
      if (!transformExt(message.ext)) return

      messages.unshift(makeHistoryMessage(message, otherAff))
    })
  }

  function makeHistoryMessage(message, otherAff) {
    const ext = JSON.parse(message.ext)
    const self = otherAff === ext.toAff

    return buildMessageWithLangTable({
      _id: message.id, // 這才是後端產生的真正訊息id，但我當初發送的時候只能用發送端的 sign 當成他的 id，所以還是保留這種情況
      id: message.sign,
      timestamp: toDate(message.created_at),
      content: message.content,
      contentType: message.content_type || 'text', // 據說如果是 text 的話後端可能會傳空字串
      ext,
      self,
      status: SEND_STATUS.SUCCESS,
      unread: !self && !!message.need_send, // need_send 0已讀 1未讀
    })
  }

  function buildMessageWithLangTable(message) {
    if (
      // 是對方
      !message.self &&
      // 是文字訊息
      message.contentType === 'text' &&
      typeof message.ext.type === 'undefined' &&
      typeof message.ext.donateAmount === 'undefined'
    ) {
      message.langTable = locales.reduce(
        (a, c) => {
          a[c.value] = TRANSLATE_STATUS.PENDING
          return a
        },
        { orig: message.content },
      )
    }
    return message
  }

  async function initUser(id, uuid, avatar, username, nickname, isVip, tier, messages = []) {
    const { getCreator } = useCreatorStore()
    const creator = await getCreator(id)
    userMap.set(id, {
      id,
      uuid,
      avatar,
      username,
      nickname,
      isVip,
      tier: creator.tier || 1,
      translate: false,
      translateLang: locale.value,
      messages,
      loading: false,
      noMore: false,
    })
    userHistoryFetcherMap.set(
      id,
      useInfinite({
        request: API.Chat.getHistory,
        params: { from_uuid: uuid },
        limit: 20,
      }),
    )
  }

  function clearALL() {
    userMap.clear()
    sendingMessagesMap.clear()
  }

  function transformExt(ext) {
    if (ext === 'Array') {
      console.warn('chat message ext error', ext)
      return false
    }
    try {
      return JSON.parse(ext)
    } catch (e) {
      console.warn('chat message ext error', e)
      return false
    }
  }

  /**
   * @param {*} toLang 沒給代表直接翻譯當前語言，有給代表切換過去該語言
   */
  function translate(userId, toLang = null) {
    if (typeof userId !== 'number') {
      return
    }
    if (!isVip.value) {
      return
    }

    const user = userMap.get(userId)

    const lang = toLang || user.translateLang

    // 找出需要被翻譯的訊息
    const needTranslateMessages = user.messages.filter(
      (m) => m.langTable && m.langTable[lang] === TRANSLATE_STATUS.PENDING,
    )

    // 將這些訊息的 langTable[lang] 改為翻譯中
    // 若為切換語言(toLang 不為 null)，將原本語言放入 orig
    const origLang = user.translateLang
    needTranslateMessages.forEach((m) => {
      m.langTable[lang] = TRANSLATE_STATUS.TRANSLATING
      if (toLang) {
        if (!user.translate) {
          m.langTable.orig = m.content
        } else if (typeof m.langTable[origLang] === 'string') {
          m.langTable.orig = m.langTable[origLang]
        }
      }
    })

    // 翻譯請求建立，後端限制每個請求最多29筆
    const translatePromises = needTranslateMessages
      .reduce((a, c, i) => {
        if (i % TRANSLATE_COUNT === 0) a.push([])
        a[a.length - 1].push(c.content)
        return a
      }, [])
      .map((text) => API.Chat.translate({ data: { text, target: LANGUAGE[lang] } }))

    // 處理翻譯取得結果
    Promise.allSettled(translatePromises).then((results) =>
      results.forEach((result, i) => {
        const originMessages = needTranslateMessages.slice(TRANSLATE_COUNT * i, TRANSLATE_COUNT * i + TRANSLATE_COUNT)
        if (result.status === 'fulfilled') {
          originMessages.forEach((m, i) => (m.langTable[lang] = result.value.text[i]))
        }
        if (result.status === 'rejected') {
          originMessages.forEach((m) => (m.langTable[lang] = TRANSLATE_STATUS.PENDING))
          console.error(`Translate error <${lang}>: ${result.reason} `)
        }
      }),
    )

    // // 假裝翻譯
    // setTimeout(
    //   () => needTranslateMessages.forEach((m) => (m.langTable[lang] = `<${lang}> ${m.content} <${lang}>`)),
    //   300,
    // )

    user.translate = true
    user.translateLang = lang
  }

  function unTranslate(userId) {
    if (typeof userId !== 'number') {
      return
    }
    const user = userMap.get(userId)
    user.translate = false
  }

  function translateWhenNewMessage(user) {
    if (user.translate) {
      requestAnimationFrame(() => translate(user.id))
    }
  }

  const { chatBuy, chatSubscribe } = useDialog()

  const _currentChatCreator = ref(null)
  function setChatCreator(creator) {
    _currentChatCreator.value = creator
  }
  function clearChatCreator() {
    _currentChatCreator.value = null
  }

  function $chatBuy(item) {
    chatBuy({ item, creator: _currentChatCreator.value })
  }

  function $chatSubscribe(item) {
    chatSubscribe({ item })
  }

  return {
    usersSortByLatestMessage,
    totalUnreadCount: readonly(totalUnreadCount),
    ready: readonly(ready),
    getUser,
    pushSelfMessage,
    selfMessageSendSuccess,
    selfPhotoUploaded,
    pushOtherMessage,
    loadNextHistory,

    supportTranslate: readonly(isVip),
    translatorOpen: readonly(translatorOpen),
    openTranslator,
    closeTranslator,
    toggleTranslator,
    translate,
    unTranslate,

    currentChatCreator: readonly(_currentChatCreator),
    setChatCreator,
    clearChatCreator,
    $chatBuy,
    $chatSubscribe,
  }
})
